using System;
using System.IO;
using System.Text;
using UnityEngine;

public class TextUtil
{
    public enum EncodingType
    {
        Unknown,
        UTF8,
        BigEndianUnicode,
        Unicode,
        ASCII,
        GBK
    }
    
    public static Encoding UTF8
    {
        get { return Encoding.UTF8; }
    }

    public static Encoding GBK
    {
        get { return Encoding.GetEncoding("GBK"); }
    }

    public static Encoding ANSI_CHINESE
    {
        get { return Encoding.GetEncoding("gb2312"); }
    }

    /// <summary>
    /// 猜测文件Encoding
    /// </summary>
    /// <param name="filename"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public static EncodingType GuessFileEncoding(string filename)
    {
        if (!File.Exists(filename))
        {
            throw new Exception("文件 " + filename + " 不存在!");
        }
        using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
        {
            return GuessStreamEncoding(fs);
        }
    }

    /// <summary>
    /// 获取Encoding
    /// </summary>
    /// <param name="encodingType"></param>
    /// <returns></returns>
    public static Encoding GetEncoding(EncodingType encodingType)
    {
        switch (encodingType)
        {
            case EncodingType.Unicode:
                return Encoding.Unicode;
            case EncodingType.BigEndianUnicode:
                return Encoding.BigEndianUnicode;
            case EncodingType.UTF8:
                return Encoding.UTF8;
            default:
                return Encoding.Default;
        }
    }

    /// <summary>
    /// 猜测文件流Encoding
    /// </summary>
    /// <param name="stream"></param>
    /// <returns></returns>
    public static EncodingType GuessStreamEncoding(Stream stream)
    {
        var br = new BinaryReader(stream);
        int headCount = Mathf.Min(100,(int)stream.Length);//不用全部字节检测
        var bytes = br.ReadBytes(headCount);
        br.Close();
        return GuessStreamEncoding(bytes);
    }

    /// <summary>
    /// 猜测文件流Encoding
    /// </summary>
    /// <param name="buffers"></param>
    /// <returns></returns>
    public static EncodingType GuessStreamEncoding(byte[] buffers)
    {
        if (buffers[0] == 0xFE && buffers[1] == 0xFF)//FE FF 254 255  UTF-16 BE (big-endian)
        {
            return EncodingType.BigEndianUnicode;
        }

        if (buffers[0] == 0xFF && buffers[1] == 0xFE)//FF FE 255 254  UTF-16 LE (little-endian)
        {
            return EncodingType.Unicode;
        }
        if (IsUTF8BytesWithBom(buffers))//EF BB BF 239 187 191 UTF-8 
        {
            return EncodingType.UTF8;//with BOM
        }

        if (IsUtf8WithoutBom(buffers))
        {
            return EncodingType.UTF8;//without BOM
        }
        if (IsPlainASCII(buffers))
        {
            return EncodingType.ASCII; //默认返回ascii编码
        }
        return EncodingType.Unknown;
    }

    public static bool IsUTF8BytesWithBom(byte[] ss)
    {
        if (ss[0] == 0xEF && ss[1] == 0xBB && ss[2] == 0xBF) return true;
        return false;
    }

    public static bool IsUtf8WithoutBom(byte[] data)
    {
        int charByteCounter = 1;　 
        byte curByte; 
        for (int i = 0; i < data.Length; i++)
        {
            curByte = data[i];
            if (charByteCounter == 1)
            {
                if (curByte >= 0x80)
                {
                    while (((curByte <<= 1) & 0x80) != 0)
                    {
                        charByteCounter++;
                    }
                    　
                    if (charByteCounter == 1 || charByteCounter > 6)
                    {
                        return false;
                    }
                }
            }
            else
            {
                if ((curByte & 0xC0) != 0x80)
                {
                    return false;
                }
                charByteCounter--;
            }
        }
        if (charByteCounter > 1)
        {
            //throw new Exception("Error byte format");
        }
        return true;
    }

    public static bool IsPlainASCII(byte[] buffers)
    {
        bool isAllASCII = true;
        long totalLength = buffers.Length;
        for (long i = 0; i < totalLength; i++)
        {
            byte b = buffers[i];
            /*
             * 原理是
             * 0x80     1000 0000
             * &
             * 0x75 (p) 0111 0101
             * ASCII字符都比128小，与运算自然都是0
             */
            if ((b & 0x80) != 0)// (1000 0000): 值小于0x80的为ASCII字符    
            {
                isAllASCII = false;
                break;
            }
        }
        return isAllASCII;
    }

    /// <summary>
    /// 读取文件
    /// </summary>
    /// <param name="path"></param>
    /// <param name="encoding"></param>
    /// <returns></returns>
    public static string ReadFile(string path, Encoding encoding)
    {
        using (StreamReader sr = new StreamReader(path, encoding, true))
        {
            return sr.ReadToEnd();
        }
    }
    /// <summary>
    /// 读取文件
    /// </summary>
    /// <param name="stream"></param>
    /// <param name="encoding"></param>
    /// <returns></returns>
    public static string ReadStream(Stream stream, Encoding encoding)
    {
        if (!stream.CanRead)
        {
            return null;
        }
        using (StreamReader sr = new StreamReader(stream, encoding, true))
        {
            return sr.ReadToEnd();
        }
    }
    /// <summary>
    /// 很巧妙的判断方式
    /// </summary>
    /// <param name="fileName"></param>
    /// <returns></returns>
    /// <remarks>参考：https://blog.csdn.net/capricio/article/details/83023828</remarks>
    public static Encoding IsGBKOrUTF8(string fileName)
    {
        var utf8Str = ReadFile(fileName, UTF8);
        var gbkStr = ReadFile(fileName, GBK);
        return utf8Str.Length <= gbkStr.Length ? UTF8 : GBK;
    }
}